home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 2
/
Nebula Two.iso
/
Drivers
/
AnotherPAS_ForAudioCD
/
ProAudioSpectrumInline.h
< prev
Wrap
Text File
|
1994-01-29
|
20KB
|
859 lines
/*
* Copyright (c) 1993 NeXT Computer, Inc. All rights reserved.
*/
#import "ProAudioSpectrumRegisters.h"
#import <driverkit/i386/ioPorts.h>
#import <driverkit/generalFuncs.h>
static inline
void
setBaseAddress(unsigned int baseAddress)
{
/*
* To relocate the I/O addresses, two 8-bit values are written to the
* Master Address Pointer (0x9a01):
* (1) board ID value (valid settings are 0xbc-0xbf)
* (2) base address shifted right by two positions
*/
outb(MASTER_ADDRESS_POINTER, FIRST_BOARD_ID);
outb(MASTER_ADDRESS_POINTER, (baseAddress) >> 2);
}
static inline
filterControl_t
getFilterControl()
{
union {
filterControl_t reg;
unsigned char data;
} filterControl;
filterControl.data = inb(FILTER_CONTROL);
return (filterControl.reg);
}
static inline
void
setFilterControl(filterControl_t reg)
{
union {
filterControl_t reg;
unsigned char data;
} filterControl;
filterControl.reg = reg;
outb(FILTER_CONTROL, filterControl.data);
}
static inline
void
enableAudioOutput(boolean_t enable)
{
filterControl_t filterControl = {0};
filterControl = getFilterControl();
filterControl.enableAudioOutput = enable;
setFilterControl(filterControl);
}
static inline
interruptControl_t
getInterruptControl()
{
union {
interruptControl_t reg;
unsigned char data;
} interruptControl;
interruptControl.data = inb(INTERRUPT_CONTROL);
return (interruptControl.reg);
}
static inline
void
setInterruptControl(interruptControl_t reg)
{
union {
interruptControl_t reg;
unsigned char data;
} interruptControl;
interruptControl.reg = reg;
outb(INTERRUPT_CONTROL, interruptControl.data);
}
static inline
interruptStatus_t
getInterruptStatus()
{
union {
interruptStatus_t reg;
unsigned char data;
} interruptStatus;
interruptStatus.data = inb(INTERRUPT_STATUS);
return (interruptStatus.reg);
}
static inline
void
setInterruptStatus(interruptStatus_t reg)
{
union {
interruptStatus_t reg;
unsigned char data;
} interruptStatus;
interruptStatus.reg = reg;
outb(INTERRUPT_STATUS, interruptStatus.data);
}
static inline
crossChannelControl_t
getCrossChannelControl()
{
union {
crossChannelControl_t reg;
unsigned char data;
} crossChannelControl;
crossChannelControl.data = inb(CROSS_CHANNEL_CONTROL);
return (crossChannelControl.reg);
}
static inline
void
setCrossChannelControl(crossChannelControl_t reg)
{
union {
crossChannelControl_t reg;
unsigned char data;
} crossChannelControl;
crossChannelControl.reg = reg;
outb(CROSS_CHANNEL_CONTROL, crossChannelControl.data);
}
static inline
sampleCounterControl_t
getSampleCounterControl()
{
union {
sampleCounterControl_t reg;
unsigned char data;
} sampleCounterControl;
sampleCounterControl.data = inb(SAMPLE_COUNTER_CONTROL);
return (sampleCounterControl.reg);
}
static inline
void
setSampleCounterControl(sampleCounterControl_t reg)
{
union {
sampleCounterControl_t reg;
unsigned char data;
} sampleCounterControl;
sampleCounterControl.reg = reg;
outb(SAMPLE_COUNTER_CONTROL, sampleCounterControl.data);
}
static inline
systemConfiguration1_t
getSystemConfiguration1()
{
union {
systemConfiguration1_t reg;
unsigned char data;
} systemConfiguration1;
systemConfiguration1.data = inb(SYSTEM_CONFIGURATION_1);
return (systemConfiguration1.reg);
}
static inline
void
setSystemConfiguration1(systemConfiguration1_t reg)
{
union {
systemConfiguration1_t reg;
unsigned char data;
} systemConfiguration1;
systemConfiguration1.reg = reg;
outb(SYSTEM_CONFIGURATION_1, systemConfiguration1.data);
}
static inline
systemConfiguration2_t
getSystemConfiguration2()
{
union {
systemConfiguration2_t reg;
unsigned char data;
} systemConfiguration2;
systemConfiguration2.data = inb(SYSTEM_CONFIGURATION_2);
return (systemConfiguration2.reg);
}
static inline
void
setSystemConfiguration2(systemConfiguration2_t reg)
{
union {
systemConfiguration2_t reg;
unsigned char data;
} systemConfiguration2;
systemConfiguration2.reg = reg;
outb(SYSTEM_CONFIGURATION_2, systemConfiguration2.data);
}
static inline
DMAChannelConfiguration_t
getDMAChannelConfiguration()
{
union {
DMAChannelConfiguration_t reg;
unsigned char data;
} DMAChannelConfiguration;
DMAChannelConfiguration.data = inb(DMA_CHANNEL_CONFIGURATION);
return (DMAChannelConfiguration.reg);
}
static inline
void
setDMAChannelConfiguration(DMAChannelConfiguration_t reg)
{
union {
DMAChannelConfiguration_t reg;
unsigned char data;
} DMAChannelConfiguration;
DMAChannelConfiguration.reg = reg;
outb(DMA_CHANNEL_CONFIGURATION, DMAChannelConfiguration.data);
}
static inline
boolean_t
setDMAChannel(int channel)
{
static DMAChannelConfiguration_t DMAChannelConfiguration = {0};
static const unsigned char DMAMap[] = {
DMA_CHANNEL_0,
DMA_CHANNEL_1,
DMA_CHANNEL_2,
DMA_CHANNEL_3,
DMA_CHANNEL_NONE,
DMA_CHANNEL_5,
DMA_CHANNEL_6,
DMA_CHANNEL_7,
};
if (DMAMap[channel] == DMA_CHANNEL_NONE)
return FALSE;
DMAChannelConfiguration.channel = DMAMap[channel];
setDMAChannelConfiguration(DMAChannelConfiguration);
return TRUE;
}
static inline
IRQConfiguration_t
getIRQConfiguration()
{
union {
IRQConfiguration_t reg;
unsigned char data;
} IRQConfiguration;
IRQConfiguration.data = inb(IRQ_CONFIGURATION);
return (IRQConfiguration.reg);
}
static inline
void
setIRQConfiguration(IRQConfiguration_t reg)
{
union {
IRQConfiguration_t reg;
unsigned char data;
} IRQConfiguration;
IRQConfiguration.reg = reg;
outb(IRQ_CONFIGURATION, IRQConfiguration.data);
}
static inline
boolean_t
setInterrupt(int interrupt)
{
static IRQConfiguration_t IRQConfiguration = {0};
static const unsigned char IRQMap[] = {
INTERRUPT_NONE,
INTERRUPT_NONE,
INTERRUPT_2,
INTERRUPT_3,
INTERRUPT_4,
INTERRUPT_5,
INTERRUPT_6,
INTERRUPT_7,
INTERRUPT_NONE,
INTERRUPT_NONE,
INTERRUPT_10,
INTERRUPT_11,
INTERRUPT_12,
INTERRUPT_NONE,
INTERRUPT_14,
INTERRUPT_15
};
if (IRQMap[interrupt] == INTERRUPT_NONE)
return FALSE;
IRQConfiguration.interrupt = IRQMap[interrupt];
setIRQConfiguration(IRQConfiguration);
return TRUE;
}
static inline
void
setMasterOutputAttenuation(u_int channel, masterAttenuation_t attenuation)
{
union {
channelSelection_t reg;
unsigned char data;
} channelSelection;
// avoid a warning
channelSelection.data = 0;
// select the master A mixer
channelSelection.reg.selectAddress = MIXER_A_MASTER;
channelSelection.reg.selectChannel = channel;
channelSelection.reg.isTransfer = TRUE;
outb(MIXER_CONTROL, channelSelection.data);
// set the attenuation
outb(MIXER_CONTROL, (char)attenuation);
}
static inline
void
setOutputAttenuation(u_int address, u_int channel, u_int attenuation)
{
union {
channelSelection_t reg;
unsigned char data;
} channelSelection;
union {
channelAttenuation_t reg;
unsigned char data;
} channelAttenuation;
// avoid a warning
channelSelection.data = 0;
channelAttenuation.data = 0;
channelSelection.reg.selectAddress = address;
channelSelection.reg.selectChannel = channel;
channelSelection.reg.isTransfer = TRUE;
outb(MIXER_CONTROL, channelSelection.data);
channelAttenuation.reg.attenuation = attenuation;
channelAttenuation.reg.routeChannel = MIXER_A_ROUTE;
channelAttenuation.reg.swapChannels = NORMAL_STEREO;
outb(MIXER_CONTROL, channelAttenuation.data);
}
static inline
void
setMasterInputAttenuation(u_int channel, masterAttenuation_t attenuation)
{
union {
channelSelection_t reg;
unsigned char data;
} channelSelection;
// avoid a warning
channelSelection.data = 0;
// select the master B mixer
channelSelection.reg.selectAddress = MIXER_B_MASTER;
channelSelection.reg.selectChannel = channel;
channelSelection.reg.isTransfer = TRUE;
outb(MIXER_CONTROL, channelSelection.data);
// set the attenuation
outb(MIXER_CONTROL, (char)attenuation);
}
static inline
void
setInputAttenuation(u_int address, u_int channel, u_int attenuation)
{
union {
channelSelection_t reg;
unsigned char data;
} channelSelection;
union {
channelAttenuation_t reg;
unsigned char data;
} channelAttenuation;
// avoid a warning
channelSelection.data = 0;
channelAttenuation.data = 0;
channelSelection.reg.selectAddress = address;
channelSelection.reg.selectChannel = channel;
channelSelection.reg.isTransfer = TRUE;
outb(MIXER_CONTROL, channelSelection.data);
channelAttenuation.reg.attenuation = attenuation;
channelAttenuation.reg.routeChannel = MIXER_B_ROUTE;
channelAttenuation.reg.swapChannels = NORMAL_STEREO;
outb(MIXER_CONTROL, channelAttenuation.data);
}
/*
* In the 3.1 release, the driver set the sample rate using the technique
* described in the Developer Reference. Unfortunately, this was imprecise
* due to rounding errors. The values were calculated as follows:
*
* 1193180 / (sample rate * channel count)
* 1193180 / (44100 * 1) = 27 // 44.1 kHz mono
* 1193180 / (44100 * 2) = 13 // 44.1 kHz stereo
*
* MediaVision has provided us with the calculateRate function which calculates
* the sample rate with more precision. This technique (which also sets the
* prescale register) is undocumented in their reference manual.
*
*/
static inline
void
calculateRate(u_int sampleRate, u_int *timer, u_int *prescale)
{
long targetRatio;
long bestRatio;
long testRatio;
long bestDifference;
long lastDifference;
long testDifference;
long p;
long t;
targetRatio = (441000L << 10) / sampleRate;
bestRatio = 300L << 10;
bestDifference = 7000L << 10;
*prescale = 0;
*timer = 0;
for (p = 2; p < 256; p++) {
lastDifference = 300L << 10;
for (t = p+1; t < 256; t++) {
testRatio = (t << 10) / p;
if (testRatio == targetRatio) {
bestRatio = testRatio;
*prescale = p;
*timer = t;
return;
}
testDifference = testRatio - targetRatio;
if (testDifference < 0)
testDifference = -testDifference;
if (testDifference > lastDifference)
break;
if (testDifference < bestDifference) {
bestRatio = testRatio;
bestDifference = testDifference;
*prescale = p;
*timer = t;
}
lastDifference = testDifference;
}
}
}
static inline
void
setSampleRateTimer(u_int rate)
{
u_int prescale;
u_int timer;
union {
sampleRateTimer_t rate;
unsigned char data[2];
} sampleRateTimer;
filterControl_t filterControl = {0};
sampleCounterControl_t sampleCounterControl = {0};
/*
* Before setting the sample rate interval, be sure to select the
* Sample Rate Timer using Local Timer Control Register (0x138b). Also
* remember to set the Sample Rate Timer Gate of the Audio Filter Control
* Register (0xb8a) to 0 before programming the timer.
*/
filterControl = getFilterControl();
filterControl.enableSampleRateTimer = FALSE;
setFilterControl(filterControl);
sampleCounterControl.countFormat = BINARY_COUNT_FORMAT;
sampleCounterControl.selectMode = SAMPLE_RATE_MODE;
sampleCounterControl.latchCounter = 3;
sampleCounterControl.selectCounter = SAMPLE_RATE_COUNT;
setSampleCounterControl(sampleCounterControl);
switch (rate) {
case 44100:
timer = 20;
prescale = 2;
break;
case 22050:
timer = 40;
prescale = 2;
break;
case 8012:
timer = 110;
prescale = 2;
break;
default:
calculateRate(rate, &timer, &prescale);
break;
}
sampleRateTimer.rate = timer;
outb(SAMPLE_RATE_TIMER, sampleRateTimer.data[0]);
outb(SAMPLE_RATE_TIMER, sampleRateTimer.data[1]);
outb(PRESCALE_DIVIDER, prescale & 0x0F);
}
static inline
void
setSampleBufferCounter(sampleBufferCounter_t count)
{
union {
sampleBufferCounter_t count;
unsigned char data[2];
} sampleBufferCounter;
filterControl_t filterControl = {0};
sampleCounterControl_t sampleCounterControl = {0};
filterControl = getFilterControl();
filterControl.enableSampleBufferCounter = FALSE;
setFilterControl(filterControl);
sampleCounterControl.countFormat = BINARY_COUNT_FORMAT;
sampleCounterControl.latchCounter = 3;
sampleCounterControl.selectMode = SAMPLE_BUFFER_MODE;
sampleCounterControl.selectCounter = SAMPLE_BUFFER_COUNT;
setSampleCounterControl(sampleCounterControl);
sampleBufferCounter.count = count;
outb(SAMPLE_BUFFER_COUNTER, sampleBufferCounter.data[0]);
outb(SAMPLE_BUFFER_COUNTER, sampleBufferCounter.data[1]);
}
static inline
void
setMasterModeControl(masterModeControl_t mode)
{
union {
masterModeControl_t reg;
unsigned char data;
} masterModeControl;
union {
channelSelection_t reg;
unsigned char data;
} channelSelection;
// avoid a warning
channelSelection.data = 0;
channelSelection.reg.selectAddress = MASTER_MODE_CONTROL;
channelSelection.reg.selectChannel = BOTH_CHANNELS;
channelSelection.reg.isTransfer = TRUE;
outb(MIXER_CONTROL, channelSelection.data);
masterModeControl.reg = mode;
outb(MIXER_CONTROL, masterModeControl.data);
}
static inline
void
setLoudnessFilter(boolean_t flag)
{
masterModeControl_t masterModeControl = {0};
masterModeControl.loudnessFilter = flag;
setMasterModeControl(masterModeControl);
}
static inline
void
setBassControl(unsigned char boost)
{
union {
channelSelection_t reg;
unsigned char data;
} channelSelection;
// avoid a warning
channelSelection.data = 0;
channelSelection.reg.selectAddress = BASS_CONTROL;
channelSelection.reg.selectChannel = BOTH_CHANNELS;
channelSelection.reg.isTransfer = TRUE;
outb(MIXER_CONTROL, channelSelection.data);
outb(MIXER_CONTROL, boost);
}
static inline
void
setTrebleControl(unsigned char boost)
{
union {
channelSelection_t reg;
unsigned char data;
} channelSelection;
// avoid a warning
channelSelection.data = 0;
channelSelection.reg.selectAddress = TREBLE_CONTROL;
channelSelection.reg.selectChannel = BOTH_CHANNELS;
channelSelection.reg.isTransfer = TRUE;
outb(MIXER_CONTROL, channelSelection.data);
outb(MIXER_CONTROL, boost);
}
static inline
void
resetMixer()
{
setMasterOutputAttenuation(BOTH_CHANNELS,
DEFAULT_MASTER_OUTPUT_ATTENUATION);
setOutputAttenuation(PCM,
BOTH_CHANNELS,
DEFAULT_OUTPUT_ATTENUATION);
/*
* mute all other output channels
*/
/* Don't mute this so that CD-Audio can get through, I have no idea why.
* Modified 12/8/94 Jason LaPierre
*/
/**
muting loopback makes so inputs are not looped back through
the main output.
I changed the attenuation level to the maximum.
Modified by Scott Bender 01/29/94
**/
setOutputAttenuation(INPUT_MIXER_LOOPBACK,
BOTH_CHANNELS,
DEFAULT_MICROPHONE_ATTENUATION);
setMasterInputAttenuation(BOTH_CHANNELS,
DEFAULT_MASTER_INPUT_ATTENUATION);
setInputAttenuation(MICROPHONE,
BOTH_CHANNELS,
DEFAULT_MICROPHONE_ATTENUATION);
/**
Set external line in attenuation to max value
Changed by Scott Bender 1/29/94
**/
setInputAttenuation(EXTERNAL_LINE_IN,
BOTH_CHANNELS,
DEFAULT_MICROPHONE_ATTENUATION);
/*
* mute all other input channels
*/
setInputAttenuation(FM_SYNTHESIS,
BOTH_CHANNELS,
MUTE);
/* Don't mute internal jack so that CD-Audio can get through
* Modified 12/8/94 Jason LaPierre
*/
/**
I went ahead and set this to the max
Modified bt Scott Bender 1/29/94
(this has not been tested)
**/
setInputAttenuation(INTERNAL_LINE_IN,
BOTH_CHANNELS,
DEFAULT_MICROPHONE_ATTENUATION);
setInputAttenuation(SPEAKER,
BOTH_CHANNELS,
MUTE);
setInputAttenuation(SOUNDBLASTER,
BOTH_CHANNELS,
MUTE);
/*
* set treble and bass boost to 0db
*/
setBassControl(DEFAULT_BASS_BOOST);
setTrebleControl(DEFAULT_TREBLE_BOOST);
}
/*
* resetHardware uses "magic" values recommended by MediaVision. These
* settings are not always documented in the reference guide. In addition,
* some of the values are specific to a particular version of the hardware.
*/
static inline
boolean_t
resetHardware()
{
systemConfiguration1_t systemConfiguration1;
union {
interruptControl_t reg;
unsigned char data;
} interruptControl;
unsigned char version;
/*
* The presence of the hardware is verified. The version bits in the
* interrupt control register are read only.
*/
interruptControl.data = inb(INTERRUPT_CONTROL);
if (interruptControl.data == 0xff)
return FALSE;
version = interruptControl.reg.version;
interruptControl.reg.version = 0;
outb(INTERRUPT_CONTROL, interruptControl.data);
interruptControl.data = inb(INTERRUPT_CONTROL);
if (interruptControl.reg.version != version)
return FALSE;
/*
* Turn off MPU and SoundBlaster emulation
*
outb(COMPATIBILITY_ENABLE, 0);
/*
* Turn off MPU and SoundBlaster interrupts
*/
outb(EMULATION_CONFIGURATION, 0);
/*
* Sets wait state to 140ns period
*/
outb(WAIT_STATE, WAIT_STATE_RESET);
/*
* D0 - resets FM
* D1 - resets Codec
* D2 - resets SoundBlaster
* D4 - resets MVA508 Mixer
*/
outb(AUDIO_MIXER, 0);
outb(AUDIO_MIXER, AUDIO_MIXER_RESET);
/*
* This is required when using the prescale register for more precise
* sample rate timing.
*/
systemConfiguration1 = getSystemConfiguration1();
systemConfiguration1.selectCompatibleClock = TRUE;
setSystemConfiguration1(systemConfiguration1);
outb(SYSTEM_CONFIGURATION_2, SYSTEM_CONFIGURATION_2_RESET);
/*
* D3 (invert bclk output)
* D4 (use codec sync output)
*/
outb(SYSTEM_CONFIGURATION_3, SYSTEM_CONFIGURATION_3_RESET);
outb(SYSTEM_CONFIGURATION_4, SYSTEM_CONFIGURATION_4_RESET);
/*
* When a 16 bit Codec is attached, the Prescale counter is used to
* set the ratio between the incoming Codec bit clock and the outgoing
* master clock.
*/
outb(PRESCALE_DIVIDER, PRESCALE_DIVIDER_RESET);
resetMixer();
return TRUE;
}